package com.liwt.imageeditor;

import java.io.File;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Bitmap.Config;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.Path;
import android.view.MotionEvent;
import android.view.View;

public class DrawPhotoView extends View {
	/** 上下文对象* */
	private Context context;
	public Bitmap srcBitmap;
	/** 图片 */
	public Bitmap mBitmap;
	/** 绘图画布 */
	public Canvas mCanvas;
	/** 画笔路径 */
	public Path mPath;
	/** 用于初始化图片的画笔 */
	public Paint mBitmapPaint;
	/** 用于涂鸦的画笔 */
	public Paint mPaint;
	/** 是否使用画笔 **/
	private boolean useDraw = false;

	/** 颜色数组 */
	private int[][] color = null;
	private int[][] newColor = null;
	/** 记录改变颜色的位置 */
	private boolean[][] isColorFill = null;
	/** 画笔宽度 ,最好为奇数 */
	private static final int SIZE = 17;
	/** 分割的块的大小：CUBE*CUBE */
	private int CUBE = 11;
	/** 颜色数组的宽度 */
	private int mWidth = 0;
	/** 颜色数组的高度 */
	private int mHight = 0;

	/**
	 * 构造函数 ： 获取图片绘制在画布上
	 * 
	 * @param c
	 *            关联上下文
	 * @param pathName
	 *            图片路径
	 * @param zoomsize
	 *            旋转角度
	 * @param width
	 *            结果的宽度
	 * @param height
	 *            结果的高度
	 */
	public DrawPhotoView(Context c, String pathName, int width, int height) {
		super(c);
		this.context = c;
		srcBitmap = getimage(pathName, width, height);
		mBitmap = Bitmap.createBitmap(srcBitmap.getWidth(),
				srcBitmap.getHeight(), Config.ARGB_8888);
		mCanvas = new Canvas(mBitmap);
		mPath = new Path();
		mBitmapPaint = new Paint(Paint.DITHER_FLAG);
		// 设置绘图在界面上的位置
		mCanvas.drawBitmap(srcBitmap, 0, 0, mBitmapPaint);
		mPaint = new Paint();
		mPaint.setAlpha(255);
		mPaint.setAntiAlias(true);
		mPaint.setDither(true);
		mPaint.setColor(Color.BLUE);
		mPaint.setStyle(Paint.Style.STROKE);
		mPaint.setStrokeJoin(Paint.Join.ROUND);
		mPaint.setStrokeCap(Paint.Cap.ROUND);
		mPaint.setStrokeWidth(5);

		mWidth = mBitmap.getWidth();
		mHight = mBitmap.getHeight();
		color = new int[mBitmap.getWidth()][mBitmap.getHeight()];
		newColor = new int[mBitmap.getWidth()][mBitmap.getHeight()];
		isColorFill = new boolean[mBitmap.getWidth()][mBitmap.getHeight()];
		for (int y = 0; y < mBitmap.getHeight(); y++) {
			for (int x = 0; x < mBitmap.getWidth(); x++) {
				color[x][y] = mBitmap.getPixel(x, y);
				newColor[x][y] = mBitmap.getPixel(x, y);
				isColorFill[x][y] = false;
			}
		}
		newColor(newColor, color);
	}

	/**
	 * 构造函数 ： 获取图片绘制在画布上
	 * 
	 * @param c
	 *            关联上下文
	 * @param pathName
	 *            图片路径
	 * @param zoomsize
	 *            旋转角度
	 * @param width
	 *            结果的宽度
	 * @param height
	 *            结果的高度
	 */
	public DrawPhotoView(Context c, String pathName, int width, int height,
			int[][] color, int[][] newColor) {
		super(c);
		this.context = c;
		srcBitmap = getimage(pathName, width, height);
		mBitmap = Bitmap.createBitmap(srcBitmap.getWidth(),
				srcBitmap.getHeight(), Config.ARGB_8888);
		mCanvas = new Canvas(mBitmap);
		mPath = new Path();
		mBitmapPaint = new Paint(Paint.DITHER_FLAG);
		// 设置绘图在界面上的位置
		mCanvas.drawBitmap(srcBitmap, 0, 0, mBitmapPaint);
		mPaint = new Paint();
		mPaint.setAlpha(255);
		mPaint.setAntiAlias(true);
		mPaint.setDither(true);
		mPaint.setColor(Color.BLUE);
		mPaint.setStyle(Paint.Style.STROKE);
		mPaint.setStrokeJoin(Paint.Join.ROUND);
		mPaint.setStrokeCap(Paint.Cap.ROUND);
		mPaint.setStrokeWidth(5);

		mWidth = mBitmap.getWidth();
		mHight = mBitmap.getHeight();
		isColorFill = new boolean[mBitmap.getWidth()][mBitmap.getHeight()];
		this.color = color;
		this.newColor = newColor;
	}

	public int[][] getColor() {
		return color;
	}

	public int[][] getNewColor() {
		return newColor;
	}

	private Bitmap getimage(String srcPath, int newWidth, int newHeight) {
		BitmapFactory.Options newOpts = new BitmapFactory.Options();
		// 开始读入图片，此时把options.inJustDecodeBounds 设回true了
		newOpts.inJustDecodeBounds = false;
		// 此时返回bm为空
		Bitmap bitmap = getLoacalBitmap(srcPath);
		bitmap = zoomImage(bitmap, newWidth, newHeight);
		return bitmap;// 压缩好比例大小后再进行质量压缩
	}

	/**
	 * 加载本地图片
	 * 
	 * @param path
	 *            本地图片路径
	 * @return Bitmap 本地图片不存在时返回null
	 */
	public static Bitmap getLoacalBitmap(String file) {
		// 进一步判断文件是否存在
		File check = new File(file);
		// 本地图片路径不存在，返回null
		if (!check.exists()) {
			return null;
		}
		// 读取图片
		try {
			BitmapFactory.Options newOpts = new BitmapFactory.Options();
			// 开始读入图片，此时把options.inJustDecodeBounds 设回true了
			newOpts.inJustDecodeBounds = false;
			// 表示16位位图,565代表对应三原色占的位数
			newOpts.inPreferredConfig = Bitmap.Config.RGB_565;
			newOpts.inInputShareable = true;
			// 设置图片可以被回收
			newOpts.inPurgeable = true;
			return BitmapFactory.decodeFile(file, newOpts);
		} catch (Exception e) {
			e.printStackTrace();
			// 读取图片出错时返回null
			return null;
		}
	}

	/***
	 * 图片的缩放方法
	 * 
	 * @param bgimage
	 *            ：源图片资源
	 * @param newWidth
	 *            ：缩放后宽度
	 * @param newHeight
	 *            ：缩放后高度
	 * @return
	 */
	public Bitmap zoomImage(Bitmap bgimage, int newWidth, int newHeight) {
		// 获取这个图片的宽和高
		int width = bgimage.getWidth();
		int height = bgimage.getHeight();
		// 执行该缩放方法的条件有，有一边小月屏幕的大小或者图片的高度大于长度
		double x = width * newHeight;
		double y = height * newWidth;

		if (x > y) {
			newHeight = (int) (y / (double) width);
		} else if (x < y) {
			newWidth = (int) (x / (double) height);
		}

		if (newWidth > width && newHeight > height) {
			newWidth = width;
			newHeight = height;
		}
		Matrix matrix = new Matrix();
		matrix.reset();
		// 计算宽高缩放率
		float scaleWidth = ((float) newWidth) / (float) width;
		float scaleHeight = ((float) newHeight) / (float) height;
		matrix.postScale(scaleWidth, scaleHeight);
		bgimage = Bitmap.createBitmap(bgimage, 0, 0, (int) width, (int) height,
				matrix, true);
		return bgimage;
	}

	@Override
	protected void onDraw(Canvas canvas) {
		canvas.drawBitmap(mBitmap, 0, 0, mBitmapPaint);
		canvas.drawPath(mPath, mPaint);
	}

	/** 是否使用涂鸦 **/
	public void setCanDraw(boolean canUse) {
		this.useDraw = canUse;
	}

	/** 获取是否可以涂鸦 **/
	public boolean getCanDraw() {
		return this.useDraw;
	}

	/** 触摸进行涂鸦 **/
	@Override
	public boolean onTouchEvent(MotionEvent event) {
		float x = event.getX();
		float y = event.getY();

		if (useDraw) {

			switch (event.getAction()) {
			case MotionEvent.ACTION_DOWN:
				touch_start(x, y);
				invalidate();
				break;
			case MotionEvent.ACTION_MOVE:
				touch_move(x, y);
				invalidate();
				break;
			case MotionEvent.ACTION_UP:
				touch_up();
				invalidate();
				break;
			}
			return true;
		} else {
			// 如果当前触摸的位置位于图片上
			if (y > 0 && y < mBitmap.getHeight() && x > 0
					&& x < mBitmap.getWidth()) {
				for (int i = 0; i < SIZE; i++) {
					for (int j = 0; j < SIZE; j++) {
						// 当前位置的X坐标，相对于图片
						int xSet = ((int) x + mWidth - SIZE / 2 + i) % mWidth;
						// 当前位置的Y坐标，相对于图片
						int ySet = ((int) y + mHight - SIZE / 2 + j) % mHight;
						if (!(isColorFill[xSet][ySet])) {
							// 获得该位置的马赛克值
							int newC = newColor[xSet][ySet];
							// 设置改点的新颜色值
							mBitmap.setPixel(xSet, ySet, newC);
							// 标记
							isColorFill[xSet][ySet] = true;
						}
					}
				}
			}
			invalidate();
			return true;
		}
	}

	private float mX, mY;
	private static final float TOUCH_TOLERANCE = 10;

	private void touch_start(float x, float y) {
		mPath.reset();
		mPath.moveTo(x, y);
		mX = x;
		mY = y;
	}

	private void touch_move(float x, float y) {
		float dx = Math.abs(x - mX);
		float dy = Math.abs(y - mY);
		if (dx >= TOUCH_TOLERANCE || dy >= TOUCH_TOLERANCE) {
			mPath.quadTo(mX, mY, (x + mX) / 2, (y + mY) / 2);
			mX = x;
			mY = y;
		}
	}

	private void touch_up() {
		mPath.lineTo(mX, mY);
		mCanvas.drawPath(mPath, mPaint);
		mPath.reset();
	}

	/**
	 * 计算马赛克后的颜色数组，即将图片分为很多块，每块的颜色值一样。
	 * 
	 * @param dst
	 *            马赛克之后的颜色数组
	 * @param src
	 *            原来的颜色数组
	 */
	private void newColor(int[][] dst, int[][] src) {
		/** 分块的边界值，横向 */
		int xLine = src[0].length - src[0].length % CUBE;
		/** 分块的边界值，纵向 */
		int yLine = src.length
				- (src.length % CUBE == 0 ? 0 : src.length % CUBE - 1);
		/** 新的颜色值R */
		int newR[][] = new int[src.length][src[0].length];
		/** 新的颜色值G */
		int newG[][] = new int[src.length][src[0].length];
		/** 新的颜色值B */
		int newB[][] = new int[src.length][src[0].length];
		// 计算边界内的各个块的颜色值
		for (int i = 0; i < yLine; i++) {
			for (int j = 0; j < xLine; j++) {
				// 获得各个方向新的颜色值
				newR[i][j] = Color.red(src[i][j]);
				newG[i][j] = Color.green(src[i][j]);
				newB[i][j] = Color.blue(src[i][j]);
				if (j > 0) {
					if (j % CUBE != 0) {// 不是块中一行的开始位置，先累计。
						newR[i][j] += newR[i][j - 1];
						newG[i][j] += newG[i][j - 1];
						newB[i][j] += newB[i][j - 1];
					} else {// 当前为块中一行的开始,需判断是否为一个块的开始
						if (i % CUBE != 0) {// 不是块的开始
							// 继续累计
							newR[i][j] += newR[i - 1][j + CUBE - 1];
							newG[i][j] += newG[i - 1][j + CUBE - 1];
							newB[i][j] += newB[i - 1][j + CUBE - 1];
						} else {// 是块的开始，计算位于其上方的块的马赛克值
							if (i > 0) {
								// 计算上一个方块的马赛克值
								int x = i - 1, y = j + CUBE - 1;
								int R = newR[x][y] / (CUBE * CUBE);
								int G = newG[x][y] / (CUBE * CUBE);
								int B = newB[x][y] / (CUBE * CUBE);
								// 该块内的所有颜色值均为此颜色
								for (int m = 0; m < CUBE; m++) {
									for (int n = 0; n < CUBE; n++) {
										dst[x - m][y - n] = Color.rgb(R, G, B);
									}
								}
							}
						}
					}
				}
			}
		}
	}
}
